﻿using System;
namespace CoreEx.Database.Query.Expressions
{
    /// <summary>
    /// Provides a base class for visiting a <see cref="DbExpression"/> tree.
    /// </summary>
    public abstract class DbExpressionVisitor_old
    {
        /// <summary>
        /// Visits each node of the <see cref="DbExpression"/> tree and return the results as a string based SQL representation.
        /// </summary>
        /// <param name="dbExpression">The <see cref="DbExpression"/> to visit.</param>
        /// <returns><see cref="string"/></returns>
        protected virtual string Visit(DbExpression dbExpression)
        {
            var expressionType = dbExpression.ExpressionType;
            switch (expressionType)
            {
                case DbExpressionType.Function:
                    return VisitFunctionExpression((DbFunctionExpression)dbExpression);
                case DbExpressionType.Select:
                    return VisitSelectExpression((DbSelectExpression)dbExpression);
                case DbExpressionType.Update:
                    return VisitUpdateExpression((DbUpdateExpression)dbExpression);
                case DbExpressionType.Insert:
                    return VisitInsertExpression((DbInsertExpression)dbExpression);
                case DbExpressionType.Delete:
                    return VisitDeleteExpression((DbDeleteExpression)dbExpression);
                case DbExpressionType.Column:
                    return VisitColumnExpression((DbColumnExpression)dbExpression);
                case DbExpressionType.Table:
                    return VisitTableExpression((DbTableExpression)dbExpression);
                case DbExpressionType.Binary:
                    return VisitBinaryExpression((DbBinaryExpression)dbExpression);
                case DbExpressionType.Constant:
                    return VisitConstantExpression((DbConstantExpression)dbExpression);
                case DbExpressionType.Alias:
                    return VisitAliasExpression((DbAliasExpression)dbExpression);
                case DbExpressionType.Concat:
                    return VisitConcatExpression((DbConcatExpression)dbExpression);
                case DbExpressionType.Conditional:
                    return VisitConditionalExpression((DbConditionalExpression)dbExpression);
                case DbExpressionType.Exists:
                    return VisitExistsExpression((DbExistsExpression)dbExpression);
                case DbExpressionType.List:
                    return VisitListExpression((DbListExpression)dbExpression);
                case DbExpressionType.In:
                    return VisitInExpression((DbInExpression)dbExpression);
                case DbExpressionType.Query:
                    return VisitQueryExpression((DbQuery)dbExpression);
                case DbExpressionType.Join:
                    return VisitJoinExpression((DbJoinExpression)dbExpression);
                case DbExpressionType.Unary:
                    return VisitUnaryExpression((DbUnaryExpression)dbExpression);
                case DbExpressionType.OrderBy:
                    return VisitOrderByExpression((DbOrderByExpression)dbExpression);
                case DbExpressionType.Prefix:
                    return VisitPrefixExpression((DbPrefixExpression)dbExpression);
            }
            throw new ArgumentOutOfRangeException("dbExpression",
                                                  string.Format("The expression type '{0}' is not supported",
                                                                dbExpression.ExpressionType));
        }

        /// <summary>
        /// Translates the <paramref name="binaryExpression"/> into a string representation.
        /// </summary>
        /// <param name="binaryExpression">The <see cref="DbBinaryExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitBinaryExpression(DbBinaryExpression binaryExpression);

        /// <summary>
        /// Translates the <paramref name="functionExpression"/> into a string representation.
        /// </summary>
        /// <param name="functionExpression">The <see cref="DbFunctionExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected virtual string VisitFunctionExpression(DbFunctionExpression functionExpression)
        {
            switch (functionExpression.FunctionExpressionType)
            {
                case DbFunctionExpressionType.String:
                    return VisitStringFunctionExpression((DbStringFunctionExpression) functionExpression);
                case DbFunctionExpressionType.Aggregate:
                    return VisitAggregateFunctionExpression((DbAggregateFunctionExpression)functionExpression);
                case DbFunctionExpressionType.DateTime:
                    return VisitDateTimeFunctionExpression((DbDateTimeFunctionExpression)functionExpression);
                default:
                    throw new ArgumentOutOfRangeException("functionExpression", functionExpression.FunctionExpressionType, "Not supported");
            }
        }

        /// <summary>
        /// Translates the <paramref name="stringFunctionExpression"/> into a string representation.
        /// </summary>
        /// <param name="stringFunctionExpression">The <see cref="DbStringFunctionExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitStringFunctionExpression(DbStringFunctionExpression stringFunctionExpression);

        /// <summary>
        /// Translates the <paramref name="aggregateFunctionExpression"/> into a string representation.
        /// </summary>
        /// <param name="aggregateFunctionExpression">The <see cref="DbAggregateFunctionExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitAggregateFunctionExpression(DbAggregateFunctionExpression aggregateFunctionExpression);

        /// <summary>
        /// Translates the <paramref name="dateTimeFunctionExpression"/> into a string representation.
        /// </summary>
        /// <param name="dateTimeFunctionExpression">The <see cref="DbDateTimeFunctionExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitDateTimeFunctionExpression(DbDateTimeFunctionExpression dateTimeFunctionExpression);

        /// <summary>
        /// Translates the <paramref name="selectExpression"/> into a string representation.
        /// </summary>
        /// <param name="selectExpression">The <see cref="DbSelectExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitSelectExpression(DbSelectExpression selectExpression);


        /// <summary>
        /// Translates the <paramref name="updateExpression"/> into a string representation.
        /// </summary>
        /// <param name="updateExpression">The <see cref="DbUpdateExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitUpdateExpression(DbUpdateExpression updateExpression);

        /// <summary>
        /// Translates the <paramref name="insertExpression"/> into a string representation.
        /// </summary>
        /// <param name="insertExpression">The <see cref="DbInsertExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitInsertExpression(DbInsertExpression insertExpression);

        /// <summary>
        /// Translates the <paramref name="deleteExpression"/> into a string representation.
        /// </summary>
        /// <param name="deleteExpression">The <see cref="DbDeleteExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitDeleteExpression(DbDeleteExpression deleteExpression);


        /// <summary>
        /// Translates the <paramref name="columnExpression"/> into a string representation.
        /// </summary>
        /// <param name="columnExpression">The <see cref="DbColumnExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitColumnExpression(DbColumnExpression columnExpression);

        /// <summary>
        /// Translates the <paramref name="tableExpression"/> into a string representation.
        /// </summary>
        /// <param name="tableExpression">The <see cref="DbTableExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitTableExpression(DbTableExpression tableExpression);

        /// <summary>
        /// Translates the <paramref name="constantExpression"/> into a string representation.
        /// </summary>
        /// <param name="constantExpression">The <see cref="DbConstantExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitConstantExpression(DbConstantExpression constantExpression);

        /// <summary>
        /// Translates the <paramref name="aliasExpression"/> into a string representation.
        /// </summary>
        /// <param name="aliasExpression">The <see cref="DbAliasExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitAliasExpression(DbAliasExpression aliasExpression);

        /// <summary>
        /// Translates the <paramref name="concatExpression"/> into a string representation.
        /// </summary>
        /// <param name="concatExpression">The <see cref="DbConcatExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitConcatExpression(DbConcatExpression concatExpression);

        /// <summary>
        /// Translates the <paramref name="conditionalExpression"/> into a string representation.
        /// </summary>
        /// <param name="conditionalExpression">The <see cref="DbConditionalExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitConditionalExpression(DbConditionalExpression conditionalExpression);

        /// <summary>
        /// Translates the <paramref name="existsExpression"/> into a string representation.
        /// </summary>
        /// <param name="existsExpression">The <see cref="DbExistsExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitExistsExpression(DbExistsExpression existsExpression);

        /// <summary>
        /// Translates the <paramref name="listExpression"/> into a string representation.
        /// </summary>
        /// <param name="listExpression">The <see cref="DbListExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitListExpression(DbListExpression listExpression);

        /// <summary>
        /// Translates the <paramref name="inExpression"/> into a string representation.
        /// </summary>
        /// <param name="inExpression">The <see cref="DbInExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitInExpression(DbInExpression inExpression);

        
        /// <summary>
        /// Translates the <paramref name="query"/> into a string representation.
        /// </summary>
        /// <param name="query">The <see cref="DbInExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected virtual string VisitQueryExpression(DbQuery query)
        {
            return Visit(query.GetQueryExpression());
        }

        /// <summary>
        /// Translates the <paramref name="joinExpression"/> into a string representation.
        /// </summary>
        /// <param name="joinExpression">The <see cref="DbJoinExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitJoinExpression(DbJoinExpression joinExpression);

        /// <summary>
        /// Translates the <paramref name="unaryExpression"/> into a string representation.
        /// </summary>
        /// <param name="unaryExpression">The <see cref="DbUnaryExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitUnaryExpression(DbUnaryExpression unaryExpression);

        /// <summary>
        /// Translates the <paramref name="orderByExpression"/> into a string representation.
        /// </summary>
        /// <param name="orderByExpression">The <see cref="DbOrderByExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitOrderByExpression(DbOrderByExpression orderByExpression);

        /// <summary>
        /// Translates the <paramref name="prefixExpression"/> into a string representation.
        /// </summary>
        /// <param name="prefixExpression">The <see cref="prefixExpression"/> to translate.</param>
        /// <returns><see cref="string"/></returns>
        protected abstract string VisitPrefixExpression(DbPrefixExpression prefixExpression);
        
    }
}
